﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

/*  Comments
 * Предмет:"Структуры и организация данных в ЭВМ"
    * 2-ой курс
     * Тема: Реализация алгебраических матриц
     * Цель: Научиться специфицировать и реализовывать алгебраические матрицы
     * Постановка задачи: Реализовать полную систему операций для работы с указанной  структурой данных.
     * Индивидуальное задание: Создать структуру данных "Разреженная матрица" c указанным набором операций (Схема 1)
     * Выполнил: студент группы ПЗ-09-1, Булакаев Артур
     * 19.10.10
     * Особенности реализации: Реализован способ хранения разреженных матриц на базе списка. Описан класс матрицы
     * с основным функционалом(см.далее), реализован интерфейс IEquatable, позволяющий сравнивать на равенство матрицы(
     * Equal). Разработан класс итератор для прохода по ненулевым элементам разреженной матрицы, различные виды 
     * конструкторов для матрицы, проведена инкапсуляция. Определены операции сложения, вычитания и произведения  
     * матриц в соответствии с алгеброй матриц.
     * 
     * 
     * 
     */
/*СПЕЦИФИКАЦИЯ абстракции данных "Разреженная матрица" 
 * Определение: Разреженная матрица - это матрица, в которой количество ненулевых элементов << n^2
 * 
 * Matrix=DATA TYPE IS CREATE,LoadFromFile, SaveToFile,CopyTo,Equals,GetEnumerator,GetElem,mup,NotNilCount,SetElem,
 * Similiar,sub,sum,ToArray
 * 
 * Операции: 
        public float GetElem(int i, int j)
         * About
         * Signals: error
         * Modifies: - 
         * Effects:Если выполнена, возвращает элемент с заданными координатами, иначе error!=null

        public int NotNilCout()
         * About
         * Signals: - 
         * Modifies: - 
         * Effects: Возвращает количество ненулевых элементов в матрице
         *
        public Matrix()
         * About
         * Signals: -
         * Modifies: Self 
         * Effects: Конструктор для пустой матрицы
         *
        public Matrix(int width, int height, List<Data> List)
         * About
         * Signals: -
         * Modifies: Self 
         * Effects: Конструктор матрицы по списку
         *
        public Matrix(string path)

        * About
         * Signals: error
         * Modifies: Self 
         * Effects: Конструктор матрицы из файла
         *
        public void CopyTo(Matrix matr)

         * About
         * Signals: -
         * Modifies: matr 
         * Effects: Конструктор матрицы путём копирования текущей
         *
        public void LoadFromFile(string path)

         * About
         * Signals: error
         * Modifies: Self 
         * Effects: Читает в матрицу из файла
         *
        public void SaveToFile(string path)
         * About
         * Signals: error
         * Modifies: -
         * Effects: Записывает матрицу в файл
         *
        //Реализация итератора://
        public iterator GetEnumerator()
         * About
         * Signals: -
         * Modifies: Self 
         * Effects: Метод возвращает новый итератор для матрицы
         *
  
        public bool Equals(Matrix elem) 
        * About
         * Signals: -
         * Modifies: -
         * Effects: true - объекты ссылаются на одну область памяти, false - на разные
         *
        public bool Similiar(Matrix elem) 
         * About
         * Signals: -
         * Modifies: -
         * Effects: true - матрицы равны по элементам, false - не равны
         *
        public Matrix sum(Matrix elm) 
         * About
         * Signals: -
         * Modifies: -
         * Effects: Возвращает результат сложения текущей матрицы с входной 
         *
        public Matrix sub(Matrix elm)
         * About
         * Signals: -
         * Modifies: -
         * Effects: Возвращает результат разности текущей матрицы с входной 
         *
        public Matrix mup(Matrix elm)
         * About
         * Signals: -
         * Modifies: -
         * Effects: Возвращает результат произведения текущей матрицы с входной 
         *
        public float[,] ToArray()
         * About
         * Signals: error
         * Modifies: -
         * Effects: Преобразовывает матрицу из схемы хранения 1(списка) в двумерный массив
         *
        public bool SetElem(int i, int j, float value)
         * About
         * Signals: error
         * Modifies: Self
         * Effects: Изменяет элемент с координатами i,j и задаёт ему значение value
         * 
 *      Определение: итератор для работы с матрицей. Перемещается по её элементам,позволяя с ними работать
 *      iterator=GENERATOR TYPE IS Create,Current,MoveNext,IsEnd
 *      
 * 
        public struct iterator // реализация действий итератора
        {
            public iterator(Matrix matr)
             * About
             * Signals: -
             * Modifies: Self 
             * Effects: Конструктор итератора для матрицы
             *
            public float Current
             * About
             * Signals: error
             * Modifies: - 
             * Effects: Возвращает текущий элемент матрицы
             *
            public bool MoveNext()
             * About
             * Signals: -
             * Modifies: currentIndex,currentHeigh,currentWidth 
             * Effects: Операция перехода на следующий ненулевой элемент
             *
            public bool IsEnd()
            * About
            * Signals: -
            * Modifies: -
            * Effects: true - итератор достиг конца матрицы, false - не достиг
            *
        }
 * 
 * 
 * 
 * 
 * 
 */


namespace Лабораторная_работа_1_СОД
{
    public struct Data
    {
        int inum;
        public int i
        {
            get
            {
                return inum;
            }
            set
            {
                inum = value;
            }
        }
        float anum;
        public float a
        {
            get
            {
                return anum;
            }
            set
            {
                anum = value;
            }
        }
        public void Clear()
        {
            inum = 0;
            anum = 0;
        }
    }
    /*ПРЕДСТАВЛЕНИЕ и РЕАЛИЗАЦИЯ
     *абстракции данных
	 *"Разреженная матрица"
     *на базе списка
     *
     * 
        Теперь опишем формально зависимости между абстрактным типом
        ("Разреженная матрица") и типом представления Matrix
        в виде важнейших комментариев реализации - функции АБСТРАКЦИИ и
        функции ИНВАРИАНТ ПРЕДСТАВЛЕНИЯ.

        Функция АБСТРАКЦИИ:
           __________________________________________________
	      |                                                  |
          |   Дескриптор                                     |
          |    ___________                                   |
          |  | Width     |                                   |
          |  |___________|                                   |
          |  | Height    |                                   |
          |  |___________|                                   |
          |  | Elems     |_____                              |
          |  |___________|     |                             |
          |                    |                             |
          |                    |                             |
          |       _____________|                             |
          |      |                                           |
          |      |_____Значения ненулевых элементов:______   |
          |      \-->|Elems[0]|_..._|Elems[size]|         |  |
          |      |________________________________________|  |
          |                                                  |
          |__________________________________________________|
     * 
     * Массив хранится в памяти как список. Каждый элемент списка - поле типа Data, содержит в себе  
     * два значения: i - адрес текущей строки, a - само значение элемента. В случае если в столбце больше нету
     * ненулевых элементов - i=0, а содержит номер следующего столбца, содержащего хотя бы один ненулевой элемент.
     * В случае, если a=0 - мы достигли конца списка. Поле width хранит количество столбцов матрицы, поле Height хранит
     * количество строк матрицы. 
     * 
     * Получение элемента матрицы с индексом Row и Col.
     * 
     * Просматриваем список до момента, когда текущие индексы строки и столбца перестанут удовлетворять условию:
     * ( (j < Col) или ( (j == Col) и (i < Row) ) ). Если остановились на элементе, для которого: j==Col и i==Row то 
     * возвращаем его значение. Иначе, искомый элемент равен нулю.
     * 
     * 
     * Функция инвариант представления: (0=<size,height,width<=sizeOf(int))и(Elems[i].a=0 если i=size)и(Elems[i].i=0
     * если в столбце нет дальше aij!=0)и(Если Elems[i].i!=0,Elems[i+1].i!=0 то Elems[i+1] в матрице стоит ниже и(или)правее 
     * чем Elems[i])и(Current<=max(Elems[i].a))и(CurrentHeight<=Height)и(CurrentWidth<=Width)и(currentIndex<=size)и
     * (если возникла ошибка, то error = текст ошибки)
     * 
     */
    class Matrix : IEquatable<Matrix>
    {
        List<Data> Elems; //список элементов матрицы

        int height; //кол-во строк в матрице
        int width; // кол-во столбцов в матрице
        int size;//кол-во элементов в реальном массиве
        string error;//строка, содержащая текст последнего сгенерированного исключения
        public int Height
        {
            get
            {
                return height;
            }
        } //поля вывода для к-ва столбцов, строк, и текста исключения
        public int Width
        {
            get
            {
                return width;
            }
        }
        public string Error
        {
            get 
            {
                return error;
            }
        }
        public float GetElem(int i, int j)
        {
            if ((i > this.Width) || (j > this.Height) || (i < 1) || (j < 1))
            {
                return 0;
                error = "Указанные индексы не входят в матрицу!";
            }
            iterator It = new iterator(this);
            while (!It.IsEnd())
            {
                if ((i == It.CurrentHeight) && (j == It.CurrentWidth))
                    return It.Current;
                if ((j < It.CurrentWidth) || ((j == It.CurrentWidth) && (i < It.CurrentHeight)))
                {
                    return 0;
                }
                It.MoveNext();
            }
            return 0;

        }
        /* About
         * Signals: error
         * Modifies: - 
         * Effects:Если выполнена, возвращает элемент с заданными координатами, иначе error!=null
         */
        public int NotNilCout()
        {
            if (this.size == 0)
                return 0;
            iterator It1 = new iterator(this);
            int n = 0;
            while (!It1.IsEnd())
            {
                n++;
                It1.MoveNext();
            }
            return n;
        }
        /* About
         * Signals: - 
         * Modifies: - 
         * Effects: Возвращает количество ненулевых элементов в матрице
         */
        public Matrix()
        {
            width = 0;
            height = 0;
            Elems = new List<Data>();
            size = 0;

        }  
        /* About
         * Signals: -
         * Modifies: Self 
         * Effects: Конструктор для пустой матрицы
         */
        public Matrix(int width, int height, List<Data> List)
        {
            Elems = new List<Data>();
            this.width = width;
            this.height = height;
            foreach (Data A in List)
            {
                Elems.Add(A);
            }
            size = Elems.Count;
        }
        /* About
         * Signals: -
         * Modifies: Self 
         * Effects: Конструктор матрицы по списку
         */
        public Matrix(string path)
        {
            Elems = new List<Data>();
            width = 0;
            height = 0;
            size = 0;
            LoadFromFile(path);
        }
        /* About
         * Signals: error
         * Modifies: Self 
         * Effects: Конструктор матрицы из файла
         */
        public void CopyTo(Matrix matr)
        {
            matr.height = this.Height;
            matr.width = this.Width;
            matr.Elems = new List<Data>();
            foreach (Data temp in Elems)
            {
                matr.Elems.Add(temp);
            }
            matr.size = matr.Elems.Count;

        }
        /* About
         * Signals: -
         * Modifies: matr 
         * Effects: Конструктор матрицы путём копирования текущей
         */
        public void LoadFromFile(string path)
        {
            Elems = new List<Data>();
            width = 0;
            height = 0;
            try
            {
                StreamReader Reader = new StreamReader(path,Encoding.ASCII);
                Data d1 = new Data();
                width = Convert.ToInt32(Reader.ReadLine());
                height = Convert.ToInt32(Reader.ReadLine());
                while (!Reader.EndOfStream)
                {
                    d1.i = Convert.ToInt32(Reader.ReadLine());
                    d1.a = Convert.ToInt32(Reader.ReadLine());
                    Elems.Add(d1);
                    if (d1.a == 0)
                        break;
                }
                size = Elems.Count;
                Reader.Close();
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
        }
        /* About
         * Signals: error
         * Modifies: Self 
         * Effects: Читает в матрицу из файла
         */
        public void SaveToFile(string path)
        {
            StreamWriter Writer= new StreamWriter(path);
            try
            {
                Writer.WriteLine(this.Height);
                Writer.WriteLine(this.Width);
                foreach (Data temp in Elems)
                {
                    Writer.WriteLine(temp.i);
                    //Writer.Write(" ");
                    Writer.WriteLine(temp.a);
                    //Writer.Write(" ");
                }

            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
            finally
            {
                Writer.Close();
            }
        }
        /* About
         * Signals: error
         * Modifies: -
         * Effects: Записывает матрицу в файл
         */
        //Реализация итератора://
        public iterator GetEnumerator()
        {
            return new iterator(this);
        }
        /* About
         * Signals: -
         * Modifies: Self 
         * Effects: Метод возвращает новый итератор для матрицы
         */
        public struct iterator // реализация действий итератора
        {
            private readonly Matrix matr;// объект матрицы
            private int currentIndex; //текущий индекс
            private int currentHeight; //текущая строка
            private int currentWidth; //текущий столбец
            public int CurrentWidth
            {
                get
                {
                    return currentWidth;
                }
            } //поля для работы с итератором
            public int CurrentHeight
            {
                get
                {
                    return currentHeight;
                }
            }
            public int Counter
            {
                get
                {
                    return currentIndex;
                }
            }
            public iterator(Matrix matr)
            {
                this.matr = matr;
                currentIndex = 0;
                if (matr.Elems[0].a != 0)
                {
                    if (matr.Elems[0].i != 0)
                    {
                        currentWidth = 1;
                        currentHeight = matr.Elems[0].i;
                    }
                    else
                    {
                        currentIndex++;
                        currentWidth = Convert.ToInt32(matr.Elems[0].a);
                        currentHeight = matr.Elems[currentIndex].i;
                    }
                }
                else
                {
                    currentWidth = 1;
                    currentHeight = 1;
                    
                }
            } 
            /* About
             * Signals: -
             * Modifies: Self 
             * Effects: Конструктор итератора для матрицы
             */
            public float Current
            {
                get 
                {
                    try
                    {
                        if (currentIndex == -1 || currentIndex == matr.size)
                            throw new InvalidOperationException();
                    }
                    catch (InvalidOperationException ex)
                    {
                        matr.error = "Ошибка при проходе по матрице!";
                        MessageBox.Show(ex.Message);
                    }

                    return matr.Elems[currentIndex].a;
                }
            }  //получение значения текущего элемента
            /* About
             * Signals: error
             * Modifies: - 
             * Effects: Возвращает текущий элемент матрицы
             */
            public bool MoveNext()
            {
                if (currentIndex < matr.size-1 )
                {
                    currentIndex++;
                    if (matr.Elems[currentIndex].i == 0)
                    {
                        currentWidth = Convert.ToInt32(matr.Elems[currentIndex].a);
                        if (currentWidth != 0)
                            currentIndex++;
                        else
                        {
                            currentWidth = matr.Width + 1;
                            currentHeight = matr.Height + 1;
                            currentIndex = matr.size;
                        }

                    }
                    if (currentIndex!=matr.size)
                        currentHeight = matr.Elems[currentIndex].i;

                }
                if(currentIndex==matr.size-1)
                    if (matr.Elems[currentIndex].a == 0)
                    {
                        currentWidth = matr.Width + 1;
                        currentHeight = matr.Height + 1;
                        currentIndex = matr.size;
                    }
                return currentIndex < matr.size;
            } //передвижение вперёд
            /* About
             * Signals: -
             * Modifies: currentIndex,currentHeigh,currentWidth 
             * Effects: Операция перехода на следующий ненулевой элемент
             */
            public bool IsEnd()
            {
                if ((currentIndex == matr.size) || (matr.Elems[0].a == 0))
                {
                    return true;
                }
                else
                    return false;
            }
            /* About
            * Signals: -
            * Modifies: -
            * Effects: true - итератор достиг конца матрицы, false - не достиг
            */
        }

        public bool Equals(Matrix elem) 
        {
            return Object.Equals(this, elem); 
        }
        /* About
         * Signals: -
         * Modifies: -
         * Effects: true - объекты ссылаются на одну область памяти, false - на разные
         */
        public bool Similiar(Matrix elem) 
        {
            if ((elem.Width!=this.Width)||(elem.Height!=this.Height))
                return false;
            iterator It1 = new iterator(this);
            iterator It2 = new iterator(elem);
            while((It1.IsEnd()!=true)||(It2.IsEnd()!=true))
            {
                if (It2.Current != It1.Current)
                    return false;
                else
                { 
                    if(It1.CurrentHeight!=It2.CurrentHeight)
                        return false;

                    if (It1.CurrentWidth !=It2.CurrentWidth)
                        return false;
                }
                It1.MoveNext();
                It2.MoveNext();
            }
            return true;
        }
        /* About
         * Signals: -
         * Modifies: -
         * Effects: true - матрицы равны по элементам, false - не равны
         */
        public Matrix sum(Matrix elm) 
        {
            if ((this.Height != elm.Height) || (this.Width != elm.Width))
                return new Matrix();
            
            List<Data> temp = new List<Data>();
            Data d1 = new Data();
            int LastWidth = 1; 
            Matrix.iterator It1 = new iterator(this);
            Matrix.iterator It2 = new iterator(elm);
            while((It1.IsEnd()!=true)||(It2.IsEnd()!=true))
            {
                if ((It1.CurrentWidth == It2.CurrentWidth) &&
                    (It1.CurrentHeight == It2.CurrentHeight))
                {
                    if (LastWidth < It1.CurrentWidth)
                    {
                        d1.i = 0;
                        d1.a = It1.CurrentWidth;
                        temp.Add(d1);
                    }
                    d1.i=It1.CurrentHeight;
                    d1.a=It1.Current+It2.Current;
                    temp.Add(d1);
                    LastWidth = It1.CurrentWidth;
                    It1.MoveNext();
                    It2.MoveNext();
                }
                else
                {
                    if (It1.CurrentWidth == It2.CurrentWidth)
                    {
                        if (It1.CurrentHeight > It2.CurrentHeight)
                        {
                            if (LastWidth < It2.CurrentWidth)
                            {
                                d1.i = 0;
                                d1.a = It2.CurrentWidth;
                                temp.Add(d1);
                            }
                            d1.a = It2.Current;
                            d1.i = It2.CurrentHeight;
                            LastWidth = It2.CurrentWidth;
                            temp.Add(d1);
                            It2.MoveNext();
                        }
                        else
                        {
                            if (LastWidth < It1.CurrentWidth)
                            {
                                d1.i = 0;
                                d1.a = It1.CurrentWidth;
                                temp.Add(d1);
                            }
                            d1.a = It1.Current;
                            d1.i = It1.CurrentHeight;
                            LastWidth = It1.CurrentWidth;
                            temp.Add(d1);
                            It1.MoveNext();
                        }
                    }
                    else
                    {
                        if (It1.CurrentWidth < It2.CurrentWidth)
                        {
                            if (LastWidth < It1.CurrentWidth)
                            {
                                d1.i = 0;
                                d1.a = It1.CurrentWidth;
                                temp.Add(d1);
                            }
                            d1.a = It1.Current;
                            d1.i = It1.CurrentHeight;
                            LastWidth = It1.CurrentWidth;
                            temp.Add(d1);
                            It1.MoveNext();
                        }
                        else
                        {
                            if (LastWidth < It2.CurrentWidth)
                            {
                                d1.i = 0;
                                d1.a = It2.CurrentWidth;
                                temp.Add(d1);
                            }
                            d1.a = It2.Current;
                            d1.i = It2.CurrentHeight;
                            LastWidth = It2.CurrentWidth;
                            temp.Add(d1);
                            It2.MoveNext();
                        }
                    }
                }
            }
            d1.i = 0;
            d1.a = 0;
            temp.Add(d1);
            Matrix n = new Matrix(this.Width,this.Height,temp);
            return n;
        }
        /* About
         * Signals: -
         * Modifies: -
         * Effects: Возвращает результат сложения текущей матрицы с входной 
         */
        public Matrix sub(Matrix elm)
        {
            if ((this.Height != elm.Height) || (this.Width != elm.Width))
                return new Matrix();
            List<Data> temp = new List<Data>();
            Data d1 = new Data();
            int LastWidth = 1;
            Matrix.iterator It1 = new iterator(this);
            Matrix.iterator It2 = new iterator(elm);
            while ((It1.IsEnd() != true) || (It2.IsEnd() != true))
            {
                if ((It1.CurrentWidth == It2.CurrentWidth) &&
                    (It1.CurrentHeight == It2.CurrentHeight))
                {
                    if (LastWidth < It1.CurrentWidth)
                    {
                        d1.i = 0;
                        d1.a = It1.CurrentWidth;
                        temp.Add(d1);
                    }
                    d1.i = It1.CurrentHeight;
                    d1.a = It1.Current - It2.Current;
                    temp.Add(d1);
                    LastWidth = It1.CurrentWidth;
                    It1.MoveNext();
                    It2.MoveNext();
                }
                else
                {
                    if (It1.CurrentWidth == It2.CurrentWidth)
                    {
                        if (It1.CurrentHeight > It2.CurrentHeight)
                        {
                            if (LastWidth < It2.CurrentWidth)
                            {
                                d1.i = 0;
                                d1.a = It2.CurrentWidth;
                                temp.Add(d1);
                            }
                            d1.a = -It2.Current;
                            d1.i = It2.CurrentHeight;
                            LastWidth = It2.CurrentWidth;
                            temp.Add(d1);
                            It2.MoveNext();
                        }
                        else
                        {
                            if (LastWidth < It1.CurrentWidth)
                            {
                                d1.i = 0;
                                d1.a = It1.CurrentWidth;
                                temp.Add(d1);
                            }
                            d1.a = It1.Current;
                            d1.i = It1.CurrentHeight;
                            LastWidth = It1.CurrentWidth;
                            temp.Add(d1);
                            It1.MoveNext();
                        }
                    }
                    else
                    {
                        if (It1.CurrentWidth < It2.CurrentWidth)
                        {
                            if (LastWidth < It1.CurrentWidth)
                            {
                                d1.i = 0;
                                d1.a = It1.CurrentWidth;
                                temp.Add(d1);
                            }
                            d1.a = It1.Current;
                            d1.i = It1.CurrentHeight;
                            LastWidth = It1.CurrentWidth;
                            temp.Add(d1);
                            It1.MoveNext();
                        }
                        else
                        {
                            if (LastWidth < It2.CurrentWidth)
                            {
                                d1.i = 0;
                                d1.a = It2.CurrentWidth;
                                temp.Add(d1);
                            }
                            d1.a = -It2.Current;
                            d1.i = It2.CurrentHeight;
                            LastWidth = It2.CurrentWidth;
                            temp.Add(d1);
                            It2.MoveNext();
                        }
                    }
                }
            }
            d1.i = 0;
            d1.a = 0;
            temp.Add(d1);
            Matrix n = new Matrix(this.Width, this.Height, temp);
            return n;
        }
        /* About
         * Signals: -
         * Modifies: -
         * Effects: Возвращает результат разности текущей матрицы с входной 
         */
        public Matrix mup(Matrix elm)
        {
            if (this.Width != elm.Height)
                return new Matrix();
            List<Data> Temp = new List<Data>();
            Data d1=new Data();
            float p = 0;
            bool notempt=false;
            int lastst=0;
            for(int k=1;k<=elm.Width;++k)
            {
                for (int j = 1; j <= elm.Width; ++j)
                { 
                    for(int i=1;i<=this.Height;++i)
                    {
                        p += this.GetElem(j, i) * elm.GetElem(i, k);  
                    }
                    if (p != 0)
                    {
                        d1.a=p;
                        d1.i=j;
                        Temp.Add(d1);
                        notempt = true;
                        p = 0;
                    }
                }
                if (notempt)
                {
                    d1.i = 0;
                    d1.a = k;
                    if (k != 1)
                        Temp.Insert(lastst, d1);
                    notempt = false;
                    lastst = Temp.Count;
                }
            }
            d1.a = 0;
            d1.i = 0;
            Temp.Add(d1);
            Matrix New = new Matrix(elm.Width, this.Height, Temp);
            return New;
        }
        /* About
         * Signals: -
         * Modifies: -
         * Effects: Возвращает результат произведения текущей матрицы с входной 
         */
        public float[,] ToArray()
        {
            float[,] a = new float[this.Width,this.Height];
            for (int i = 0; i < this.Width; ++i)
                for (int j = 0; j < this.Height; ++j)
                    a[i,j] = 0;
            if (this.size == 0)
            {
                error = "Пустая матрица!";
                return a;
            }
            iterator It=new iterator(this);
            while (!It.IsEnd())
            {
                a[It.CurrentWidth - 1, It.CurrentHeight - 1] = It.Current;
                It.MoveNext();
            }
            return a;
        }
        /* About
         * Signals: error
         * Modifies: -
         * Effects: Преобразовывает матрицу из схемы хранения 1(списка) в двумерный массив
         */
        public bool SetElem(int i, int j, float value)
        {
            if ((i > this.Width) || (j > this.Height) || (i < 1) || (j < 1))
            {
                return false;
                error = "Указанные индексы не входят в матрицу!";
            }
            iterator It = new iterator(this);
            Data d1 = new Data();
            while ((!It.IsEnd()) && ((It.CurrentWidth < j) || ((It.CurrentWidth <= j) && (It.CurrentHeight < i))))
            {
                It.MoveNext();
            }

            if (value != 0)
            {
                #region If value is not 0
                if ((It.CurrentHeight == i) && (It.CurrentWidth == j))
                {
                    d1.a = value;
                    d1.i = i;
                    Elems.RemoveAt(It.Counter);
                    Elems.Insert(It.Counter, d1);
                    return true;
                }
                else
                {
                    if (Elems[It.Counter].i != 0)
                    {

                        d1.a = value;
                        d1.i = i;
                        if (j != It.CurrentWidth)
                        {
                            Elems.Insert(It.Counter - 1, d1);
                        }
                        else
                            Elems.Insert(It.Counter, d1);
                        size++;
                        return true;
                    }
                    else
                    {
                        if (Elems[It.Counter].a != j)
                        {
                            d1.a = j;
                            d1.i = 0;
                            Elems.RemoveAt(It.Counter - 1);
                            Elems.Insert(It.Counter - 1, d1);
                        }
                        d1.a = value;
                        d1.i = i;
                        Elems.Insert(It.Counter + 1, d1);
                        size++;
                        return true;
                    }
                }
                #endregion
            }
            else
            {
                #region If value is 0, that meens we should delete this element
                if ((It.CurrentHeight == i) && (It.CurrentWidth == j))
                {
                    if ((It.Counter == 0) || (Elems[It.Counter - 1].i != 0))
                    {
                        Elems.RemoveAt(It.Counter);
                        return true;
                    }
                    else
                    {
                        if (Elems[It.Counter + 1].i != 0)
                        {
                            Elems.RemoveAt(It.Counter);
                            return true;
                        }
                        else
                        {
                            Elems.RemoveAt(It.Counter);
                            Elems.RemoveAt(It.Counter - 1);
                            return true;
                        }
                    }
                }
                else
                    return true;
                #endregion
            }
        }
        /* About
         * Signals: error
         * Modifies: Self
         * Effects: Изменяет элемент с координатами i,j и задаёт ему значение value
         */
    }
}
